﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using GameServer.Backend.Managers; //For various server managers.
using Backend.Packets;

namespace GameServer.Backend
{
    public class GameServer
    {
        /// <summary>
        /// Event exposing various server debug info.  Can be subscribed to in order to know more detailed information of server.
        /// </summary>
        public event Action<string> OnDebug;
        /// <summary>
        /// Logging Event.
        /// </summary>
        public event Action<string> OnLog;

        private List<GameClient> m_Clients;

        private TcpListener m_Listener;

        private bool m_bServerRunning;

        private int m_nServerPort;

        private short m_nClientIdCounter;

        private string m_sServerName;

        private AccountManager m_AccountManager;

        public AccountManager AccountMgr
        {
            get
            {
                return m_AccountManager;
            }
        }

        private ChatManager m_ChatManager;

        public ChatManager ChatMgr
        {
            get
            {
                return m_ChatManager;
            }
        }

        /// <summary>
        /// Exposes the Servers Name as it appears to clients.
        /// </summary>
        public string ServerName
        {
            get
            {
                return m_sServerName;
            }
        }

        public GameClient FindUser(string Login)
        {
            GameClient Return = null;

            foreach (GameClient Client in m_Clients)
                if (Client.UserName == Login)
                    Return = Client;
            return Return;
        }

        private static GameServer m_Instance;

        /// <summary>
        /// Returns the one and only game server object.
        /// </summary>
        /// <returns></returns>
        public static GameServer GetInstance()
        {
            if (m_Instance == null)
                m_Instance = new GameServer();
            return m_Instance;
        }

        private GameServer()
        {
            m_Clients = new List<GameClient>();
            m_AccountManager = new AccountManager();
            m_ChatManager = new ChatManager();
        }

        public void Debug(string DebugString)
        {
            if (OnDebug != null)
                OnDebug(DebugString + "\r\n");
        }

        private void Logger(string LogString)
        {
            if (OnLog != null)
                OnLog(LogString + "\r\n");
        }

        /// <summary>
        /// Starts the game server and all its components.
        /// </summary>
        /// <param name="ServerPort">The port to listen on for incoming connections.</param>
        /// <returns>Returns true on success.</returns>
        public bool Start(int ServerPort)
        {
            if (m_bServerRunning)
                return false;

            m_nServerPort = ServerPort;

            try
            {
                m_Listener = new TcpListener(ServerPort);
                m_Listener.Start();
                m_Listener.BeginAcceptTcpClient(OnConnect, null);
                m_bServerRunning = true;

                Logger("Listening...");
                return true;
            }
            catch (Exception Ex)
            {
                Debug("Server Startup Failed");
                Debug(Ex.Message);
                return false;
            }
        }

        public bool Stop()
        {
            if (!m_bServerRunning)
                return false;

            try
            {
                m_Listener.Stop();
                m_bServerRunning = false;
                Logger("Server Stopped.");
                return true;
            }
            catch (Exception Ex)
            {
                Debug("Server Stop Failed");
                Debug(Ex.Message);
                return false;
            }
        }

        public bool Restart()
        {
            if (!m_bServerRunning)
                return false;

            try
            {
                Stop();
                Start(m_nServerPort);
                return true;
            }
            catch (Exception Ex)
            {
                Debug("Server Restart Failed");
                Debug(Ex.Message);
                Stop();
                return false;
            }
        }

        /// <summary>
        /// To perform all necessary cleanup on the game server side when a user disconnects.
        /// </summary>
        /// <param name="Client"></param>
        public void ClientDC(GameClient Client)
        {
            Logger(Client.UserName + " Disconnected.");

            m_Clients.Remove(Client);

            m_ChatManager.ClientDC(Client);
            
        }

        /// <summary>
        /// Callback for new client connects.
        /// </summary>
        /// <param name="Ar"></param>
        private void OnConnect(IAsyncResult Ar)
        {
            try
            {
                TcpClient NewConnection = m_Listener.EndAcceptTcpClient(Ar);
                GameClient NewClient = new GameClient(m_nClientIdCounter, NewConnection);

                Logger(NewConnection.Client.RemoteEndPoint.ToString() + " Has Connected.");

                m_Clients.Add(NewClient);

                ++m_nClientIdCounter;

                m_Listener.BeginAcceptTcpClient(OnConnect, null);
            }
            catch (Exception Ex)
            {
                Stop();
            }
        }
    }
}
